#include "comm/znx_defs.h"
#include "event/znx_worker_proc.h"
#include "event/znx_aio_mgr.h"

znx_aio_manager_t aio_manager;

typedef struct {
    int                     step;
    int                     fd;
    char                    *buf;
    size_t                  buf_size;
    off_t                   offset;
    znx_aio_request_t       aio_req;
    znx_dispatch_event_t    org_dispatch_event;
} znx_test_data_t;

static inline void
znx_test_aio_handler(znx_dispatch_event_t *dispatch_event)
{
    znx_test_data_t *data = dispatch_event->data;
    znx_aio_request_t *aio_req = &data->aio_req;

    if (data->step == 0) {
        data->step++;
        znx_aio_reqeuest_init(aio_req, ZNX_AIO_READ, data->fd,
            data->buf, data->buf_size, 0, znx_test_aio_handler, data);
        znx_aio_post_event(&aio_manager, aio_req);
        znx_event_loop_async_task_incr();
        return;
    }

    if (data->step == 1) {
        znx_event_loop_async_task_decr();

        data->step++;

        if (aio_req->res.eno != 0) {
            ZNX_DEF_LOG_FATAL("aio_read failed, errno: %d", aio_req->res.eno);
        }

        ZNX_DEF_LOG_DEBUG("aio_read success, read n: %d", aio_req->res.res);
        write(STDOUT_FILENO, aio_req->buf, (size_t)aio_req->res.res);
        printf("\n");
        znx_event_loop_post_event(dispatch_event->setup_thread, dispatch_event);
        return;
    }

    if (data->step == 2) {
        data->step++;
        for (size_t i = 0; i < data->buf_size; i++) {
            data->buf[i] = 'b';
        }
        znx_aio_reqeuest_init(aio_req, ZNX_AIO_WRITE, data->fd,
            data->buf, data->buf_size, 0, znx_test_aio_handler, data);
        znx_aio_post_event(&aio_manager, aio_req);
        znx_event_loop_async_task_incr();
        return;
    }

    if (data->step == 3) {
        znx_event_loop_async_task_decr();

        data->step++;

        if (aio_req->res.eno != 0) {
            ZNX_DEF_LOG_FATAL("aio_write failed, errno: %d", aio_req->res.eno);
        }

        ZNX_DEF_LOG_DEBUG("aio_write success, write: %d", aio_req->res.res);
        znx_event_loop_post_event(dispatch_event->setup_thread, dispatch_event);
        return;
    }

    if (data->step == 4) {
        data->step++;
        znx_aio_reqeuest_init(aio_req, ZNX_AIO_READ, data->fd,
            data->buf, data->buf_size, 0, znx_test_aio_handler, data);
        znx_aio_post_event(&aio_manager, aio_req);
        znx_event_loop_async_task_incr();
        return;
    }

    if (data->step == 5) {
        znx_event_loop_async_task_decr();

        data->step++;

        if (aio_req->res.eno != 0) {
            ZNX_DEF_LOG_FATAL("aio_read failed, errno: %d", aio_req->res.eno);
        }

        ZNX_DEF_LOG_DEBUG("aio_read success, read n: %d", aio_req->res.res);
        write(STDOUT_FILENO, aio_req->buf, (size_t)aio_req->res.res);
        printf("\n");
        znx_event_loop_post_event(dispatch_event->setup_thread, dispatch_event);
        return;
    }


    ZNX_DEF_LOG_DEBUG("test done");
    znx_thread_free(data);
}

int main()
{
    znx_worker_processor_init();
    znx_worker_processor_start(1, 0, 0);

    znx_aio_manager_start(&aio_manager, 2, 2, "test");

    int fd = open("/tmp/1.txt", O_CREAT|O_RDWR, 0644);
    if (fd < 0) {
        ZNX_DEF_LOG_FATAL("open /tmp/1.txt failed, errno: %d", errno);
    }

    char buf[1024];
    for (size_t i = 0; i < sizeof(buf); i++) {
        buf[i] = 'a';
    }
    write(fd, buf, sizeof(buf));

    znx_test_data_t *test_data =
        znx_thread_calloc(sizeof(znx_test_data_t));
    test_data->fd = fd;
    test_data->buf = buf;
    test_data->buf_size = sizeof(buf);
    test_data->offset = 0;
    test_data->org_dispatch_event.handler = znx_test_aio_handler;
    test_data->org_dispatch_event.data = test_data;

    znx_worker_processor_post_event(&test_data->org_dispatch_event);

    usleep(1000);

    proc_exit = ZNX_TRUE;

    znx_aio_manager_stop(&aio_manager);

    znx_worker_processor_stop();

    close(fd);

    return 0;
}
